package com.smarttest.common.beans.protolcol;

import java.io.Serializable;

import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.smarttest.common.exceptions.NoCheckSumException;
import com.smarttest.common.exceptions.WrongLengthException;
import com.smarttest.common.util.protocol.LZ4CompressorUtil;
import com.smarttest.common.util.protocol.SmartUtils;

public class SmartMessage extends GpsMessage implements Cloneable,Serializable {

	private static final long serialVersionUID = -8096163942654297033L;
	
	private static final Logger LOG = LoggerFactory.getLogger(SmartMessage.class);
	
	// 数据分隔符
	public static final byte DELIMITER = 0x7E;
	// 扩展属性加密id
	public static final int EXTENSION_ENCRYPT_ID = 1;
	// 扩展属性分包id
	public static final int EXTENSION_PACKAGE_ID = 2;
	
	/**
	 * 消息ID, 默认值为-1，表示该消息没有成功被解析
	 */
	private int cmd = -1;
	
	/**
	 * 消息体属性
	 */
	private byte[] property;
	
	/**
	 * 二进制格式的终端唯一ID
	 */
	private byte[] byImei;

	
	/**
	 * 发送流水号
	 */
	private byte[] byOrder;
	
	private byte[] data;
	
	/**
	 * 消息校验码
	 */
	private byte checksum;
	
	private byte[] fullData;
	
	public SmartMessage() {
	}
	
	public SmartMessage(byte[] in,boolean isMandatory) throws NoCheckSumException,WrongLengthException{
		if(in == null || in.length == 0){
			return;
		}
		int len = in.length;

		checksum = SmartUtils.checksum(in, 0, len-1);
		//比较校验码
		if(checksum != in[len -1] && !isMandatory){
			throw new NoCheckSumException();
		}

		int pos = 0;
		// 读取cmd
		cmd = ((in[pos++] & 0xff) << 8) + (in[pos++] & 0xff);
		
		// 消息属性
		property = new byte[2];
		System.arraycopy(in, pos, property, 0, property.length);
		pos += 2;
		
		// 终端ID
		byImei = new byte[6];
		System.arraycopy(in, pos, byImei, 0, 6);
		imei = new String(Hex.encodeHex(byImei));
		//与布标保持一致
		imei = "107" + imei;
		pos += 6;		
		// 流水号
		byOrder = new byte[2];
		byOrder[0] = in [pos++];
		byOrder[1] = in [pos++];			
		//第14位表示扩展位，值为1时，表示存在扩展属性
		int extension=((property[0]>>5)&0x01);
		if(extension==1){
			//加密
			int encrypt=0;
			//分包数
			int packageCount=0;
			//分包序号
			int packageSeq=0;
			//扩展属性字节长度
			int extensionTotalLen=0;			
			//消息体扩展属性长度(不含本字段)
			extensionTotalLen=((in[pos++] & 0xff) << 8) + (in[pos++] & 0xff);
			int startPosition=pos;
			//extensionIdCount 扩展属性个数
			int extensionIdCount= (in[pos++]&0xff);
			for (int i=0;i<extensionIdCount;i++){
				//extensionId 扩展属性id
				int extensionId=(in[pos++]&0xff);
				int extensionLen=(in[pos++]&0xff);
				//消息体加密
				if(extensionId==EXTENSION_ENCRYPT_ID){
					encrypt=(in[pos++]&0xff);
					continue;
				}
				//消息体分包
				if(extensionId==EXTENSION_PACKAGE_ID){
				   packageCount=((in[pos++] & 0xff) << 8) + (in[pos++] & 0xff);
				   packageSeq=((in[pos++] & 0xff) << 8) + (in[pos++] & 0xff);
				   continue;
				}
			}	
			int endPosition=pos;
			if(extensionTotalLen!=(endPosition-startPosition) && !isMandatory){
				cmd = -1;
				throw new WrongLengthException();
			}
		}		
		//10-11压缩位 
		int compress=((property[0]>>2)&0x03);
		int bodyLen=len - pos -1;
		if(isMulti()){
			bodyLen += 4;
		}
		//0-9表示消息体长度
		int l = ((property[0] & 0x03)<<8) + (property[1] & 0xff);
		if(bodyLen!=l && !isMandatory){
			cmd = -1;
			throw new WrongLengthException();
		}
		fullData = in;	
		if(compress==1){			
			byte[] compressdata = new byte[bodyLen];
			System.arraycopy(in, pos, compressdata, 0, bodyLen);
			//解压-采用LZ4
			data=LZ4CompressorUtil.decompressLZ4(compressdata);
		}else{
			data = new byte[bodyLen];
			System.arraycopy(in, pos, data, 0, bodyLen);
		}				
	}
	
	public static byte[] toBytes(SmartMessage msg) {
		if(msg == null) {
			return null;
		}
		byte[] data = msg.getData();
		if(data == null || data.length == 0){
			return null;
		}
		
		byte[] bs = new byte[data.length + 15];
		int i = 0;
		bs[i++] = 0x7E;
		// 消息ID
		bs[i++] = (byte) (msg.getCmd() >> 8 & 0xff);
		bs[i++] = (byte) (msg.getCmd() & 0xff);
		// 包长
		int len = data.length;
		bs[i++] = (byte) (len >> 8 & 0xff);
		bs[i++] = (byte) (len & 0xff);
		// 终端ID
		byte[] term = msg.getByImei();
		System.arraycopy(term, 0, bs, i, term.length);
		i += term.length; 
		// 流水号
		byte[] order = msg.getByOrder();
		bs[i++] = order[0];
		bs[i++] = order[1];
		// 内容
		System.arraycopy(data, 0, bs, i, data.length);
		i += data.length;
		// 检验
		int idx = bs.length - 2;  
		bs[idx] = bs[1];
		for (int j=2;j<idx;j++) bs[idx] ^= bs[j];
		// 包尾
		bs[bs.length - 1] = 0x7E;
		
		return bs;
	}
	
	public boolean isMulti(){
		//分包消息在第14位
		return (property[1] & 0x20) == 1;
	}
	
	public String encrypted(){
		if((property[1] & 0x02) == 1) {
			return "RSA";
		}
		return null;
	}
	
	public int getOrder() {
		return (byOrder[0] << 8) + (byOrder[1] & 0xff);
	}
	
	public void setOrder(int i) {
		if(byOrder == null) {
			byOrder = new byte[2];
		}
		byOrder[0] = (byte) (i >> 8 & 0xff);
		byOrder[1] = (byte) (i & 0xff);
	}
	
	public int getCmd() {
		return cmd;
	}

	public void setCmd(int cmd) {
		this.cmd = cmd;
	}

	public byte[] getProperty() {
		return property;
	}

	public void setProperty(byte[] property) {
		this.property = property;
	}

	public byte getChecksum() {
		return checksum;
	}

	public void setChecksum(byte checksum) {
		this.checksum = checksum;
	}

	public byte[] getFullData() {
		return fullData;
	}

	public void setFullData(byte[] fullData) {
		this.fullData = fullData;
	}

	public byte[] getData() {
		return data;
	}

	public void setData(byte[] data) {
		this.data = data;
	}
	
	public byte[] getByOrder() {
		return byOrder;
	}

	public void setByOrder(byte[] byOrder) {
		this.byOrder = byOrder;
	}
	

	public SmartMessage clone(){
		SmartMessage msg = null;
		try {
			msg = (SmartMessage) super.clone();
			msg.byOrder = null;
			msg.setData(null);
		} catch (CloneNotSupportedException e) {
			LOG.error(e.getMessage(),e);
		}
		return msg;
	}

	@Override
	public Location getLocation() throws Exception {
		return null;
	}

	public byte[] getByImei() {
		return byImei;
	}

	public void setByImei(byte[] byImei) {
		this.byImei = byImei;
	}

}
